package ee.ut.veebirakendus.bot;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.log4j.Logger;

import com.sun.org.apache.bcel.internal.generic.GETSTATIC;

import ee.ut.veebirakendus.model.Card;
import ee.ut.veebirakendus.model.Hand;
import ee.ut.veebirakendus.model.HandRank;
import ee.ut.veebirakendus.model.Player;
import ee.ut.veebirakendus.model.Rank;
import ee.ut.veebirakendus.model.Suit;

public class PokerBot {

	private Logger log;

	public PokerBot() {
		log = Logger.getLogger("PokerBot");
	}

	public void giveRank(Hand hand) {
		List<Card> ofakind = new ArrayList<Card>();
		List<Card> twopair = new ArrayList<Card>();
		List<Card> flush = new ArrayList<Card>();
		List<Integer> straight = new ArrayList<Integer>();
		List<Card> highcard = new ArrayList<Card>();

		List<Card> cards = hand.getCards();
		// Check for pair, twopair, threeofakind, fullhouse, quads
		// no need to put quads last - there is no possibility for a straigth or
		// a flush
		for (Card card : cards) {
			for (Card cardtwo : cards) {
				if (card == cardtwo) {
					break;
				} else if (card.getRank() == cardtwo.getRank()) {
					if (!ofakind.contains(card)) {
						ofakind.add(card);
					}
					if (!ofakind.contains(cardtwo)) {
						ofakind.add(cardtwo);
					}
				}
			}
		}
		if (ofakind.size() == 2) {
			HandRank rank = HandRank.PAIR;
			hand.setRank(rank);
			List<Card> all = hand.getCards();
			all.removeAll(ofakind);
			if (all.size() > 2) {
				List<Card> strongest = new ArrayList<Card>();
				strongest.addAll(ofakind);
				strongest.addAll(getHighest(all, 3));
				hand.setStrongest(strongest);

				log.info("STRONGEST 5: " + hand.getStrongest());
			}

		}
		if (ofakind.size() == 3) {
			HandRank rank = HandRank.TRIPS;
			hand.setRank(rank);
			List<Card> all = hand.getCards();
			all.removeAll(ofakind);
			List<Card> strongest = new ArrayList<Card>();
			strongest.addAll(ofakind);
			strongest.addAll(getHighest(all, 2));
			hand.setStrongest(strongest);

			log.info("STRONGEST 5: " + hand.getStrongest());
		}
		if (ofakind.size() == 4) {
			if (ofakind.get(0).getRank() == ofakind.get(1).getRank()
					&& ofakind.get(1).getRank() == ofakind.get(2).getRank()) {
				HandRank rank = HandRank.QUADS;
				hand.setRank(rank);
				List<Card> all = hand.getCards();
				all.removeAll(ofakind);
				List<Card> strongest = new ArrayList<Card>();
				strongest.addAll(ofakind);
				strongest.addAll(getHighest(all, 1));
				hand.setStrongest(strongest);
			} else {
				HandRank rank = HandRank.TWOPAIR;
				hand.setRank(rank);
				List<Card> all = hand.getCards();
				all.removeAll(ofakind);
				List<Card> strongest = new ArrayList<Card>();
				strongest.addAll(ofakind);
				strongest.addAll(getHighest(all, 1));
				hand.setStrongest(strongest);

				log.info("STRONGEST 5: " + hand.getStrongest());

			}
		}
		// Check for flush
		for (Card card : cards) {
			Suit temp = card.getSuit();
			if (!flush.contains(card)) {
				flush.add(card);
			}
			for (Card cardtwo : cards) {
				if (cardtwo.getSuit() == temp) {
					if (!flush.contains(cardtwo)) {
						flush.add(cardtwo);
					}
				}
			}
			if (flush.size() < 5) {
				flush.clear();
			} else {
				break;
			}
		}
		// Check for straight
		List<Integer> temp = new ArrayList<Integer>();
		for (Card card : cards) {// get card ranks as integers
			int rankInt = getRankInt(card.getRank());
			temp.add(rankInt);
		}
		Collections.sort(temp);// sort the card values in order
		List<Integer> uniqueVals = new ArrayList<Integer>();
		for (int i : temp) { // get the unique values
			if (!uniqueVals.contains(i)) {
				uniqueVals.add(i);
			}
		}
		temp.clear(); // clean the temp array for use in next cycle
		if (uniqueVals.size() > 4) { // the size of unique values is bigger than
										// 4
			for (int i = 0; i < uniqueVals.size(); i++) {
				if (i < uniqueVals.size() - 1) { // compare the uniquevals
					if (temp.size() == 0) {
						temp.add(uniqueVals.get(i));
					} else {
						if (temp.size() >= 5) {
							straight.addAll(temp);// if the size is >=5 there is
													// a straight and set it
						}
						if (temp.get(temp.size() - 1) + 1 == uniqueVals.get(i)) {
							temp.add(uniqueVals.get(i));
						} else {
							temp.clear();
							temp.add(uniqueVals.get(i));
						}
					}

				}
			}
		}
		if (straight.size() >= 5) {
			hand.setRank(HandRank.STRAIGHT);
			List<Card> strCards = new ArrayList<Card>();
			for (int i = 0; i < straight.size(); i++) {
				for (Card card : hand.getCards()) {
					if (getRankInt(card.getRank()) == straight.get(i)) {
						strCards.add(card);
					}
				}
			}
			hand.setStrongest(strCards);
		}
		if (flush.size() > 4) {
			hand.setRank(HandRank.FLUSH);
			hand.setStrongest(flush);
		}
		if ((flush.size() > 4) && (straight.size() > 4)) {
			hand.setRank(HandRank.STRAIGHTFLUSH);
			hand.setStrongest(flush);
		}

		if (ofakind.size() == 5) {
			HandRank rank = HandRank.FULLHOUSE;
			hand.setRank(rank);
		}
		if (ofakind.size() == 0 && flush.size() == 0 && straight.size() < 5) {
			hand.setRank(HandRank.HIGHCARD);
		}

		// TODO add highcards, get pair values and so on

	}

	public Card getHighestCard(List<Card> cards) {
		Card max = cards.get(0);
		for (Card card : cards) {
			if (card.getInt() > max.getInt()) {
				max = card;
			}
		}
		return max;
	}

	public String compareHands(Player first, Player second) {
		HandRank firstRank = first.getHand().getRank();
		HandRank secondRank = second.getHand().getRank();
		int firstInt = Integer.parseInt(firstRank.handRank());
		int secondInt = Integer.parseInt(secondRank.handRank());
		String winner = "1";

		if (firstRank == secondRank) { // equal ranks to hands
			if (firstRank == HandRank.PAIR || firstRank == HandRank.TWOPAIR) {
				int firstPairCard = getRankInt(first.getHand().getStrongest()
						.get(0).getRank());// gets the first pairs rank of the
											// hand
				int secondPairCard = getRankInt(second.getHand().getStrongest()
						.get(0).getRank());
				if (firstPairCard == secondPairCard) { // doing the comparing
														// the caveman way (TODO
														// something simpler)
					int firstNextPairCardorKicker = getRankInt(first.getHand()
							.getStrongest().get(2).getRank());
					int secondNextPairCardorKicker = getRankInt(first.getHand()
							.getStrongest().get(2).getRank());
					if (firstNextPairCardorKicker == secondNextPairCardorKicker) {
						firstNextPairCardorKicker = getRankInt(first.getHand()
								.getStrongest().get(3).getRank());
						secondNextPairCardorKicker = getRankInt(first.getHand()
								.getStrongest().get(3).getRank());
						if (firstNextPairCardorKicker == secondNextPairCardorKicker) {
							firstNextPairCardorKicker = getRankInt(first
									.getHand().getStrongest().get(4).getRank());
							secondNextPairCardorKicker = getRankInt(first
									.getHand().getStrongest().get(4).getRank());
							if (firstNextPairCardorKicker == secondNextPairCardorKicker) {
								winner = "SPLIT";// end of the strongest array
													// and no different cards
							} else if (firstNextPairCardorKicker > secondNextPairCardorKicker) {
								winner = String.valueOf(first.getSeatIndex());
							} else {
								winner = String.valueOf(second.getSeatIndex());
							}
						} else if (firstNextPairCardorKicker > secondNextPairCardorKicker) {
							winner = String.valueOf(first.getSeatIndex());
						} else {
							winner = String.valueOf(second.getSeatIndex());
						}
					} else if (firstNextPairCardorKicker > secondNextPairCardorKicker) {
						winner = String.valueOf(first.getSeatIndex());
					} else {
						winner = String.valueOf(second.getSeatIndex());
					}
				} else if (firstPairCard > secondPairCard) {
					winner = String.valueOf(first.getSeatIndex());
				} else {
					winner = String.valueOf(second.getSeatIndex());
				}
			} else if (firstRank == HandRank.FLUSH
					|| firstRank == HandRank.STRAIGHT) {
				int firstHighFlushOrStr = getRankInt(first.getHand()
						.getStrongest().get(-1).getRank());
				int secondHighFlushOrStr = getRankInt(second.getHand()
						.getStrongest().get(-1).getRank());
				if (firstHighFlushOrStr == secondHighFlushOrStr) {
					winner = "SPLIT";
				} else if (firstHighFlushOrStr > secondHighFlushOrStr) {
					winner = String.valueOf(first.getSeatIndex());
				} else {
					winner = String.valueOf(second.getSeatIndex());
				}

			}
		} else {
			if (firstInt > secondInt) {
				winner = String.valueOf(first.getSeatIndex());
			} else {
				winner = String.valueOf(second.getSeatIndex());
			}
		}
		return winner;
	}

	public List<Card> getHighest(List<Card> cards, int number) {
		List<Card> highest = new ArrayList<Card>();
		while (highest.size() < number) {
			Card max = cards.get(0);
			for (Card card : cards) {
				if (card.getInt() > max.getInt()) {
					max = card;
				}
			}
			highest.add(max);
			cards.remove(max);
		}
		return highest;
	}

	public String getAction(Player player, String prevAction) {
		log.debug("Player " + player.getSeatIndex() + " hand rank: "
				+ player.getHand().getRank());
		HandRank theRank = player.getHand().getRank();
		int rankInt = Integer.parseInt(theRank.handRank());
		if (rankInt < 2 && prevAction == "raise") {
			return "fold";
		} else if (rankInt < 2
				&& (prevAction == "call" || prevAction == "newStreet")) {
			return "call";
		} else if (rankInt == 2 && prevAction == "call") {
			return "raise";
		} else if (rankInt == 2 && prevAction == "raise") {
			return "call";
		} else if (rankInt > 2) {
			return "raise";
		} else {
			return "fold";
		}
		// TODO flush ja straight draw-d
	}

	public String getPreFlopAction(Player player, String prevAction) {
		Card first = player.getFirst();
		Card second = player.getSecond();
		int intFirst = getRankInt(first.getRank());
		int intSecond = getRankInt(second.getRank());

		if (first.getRank() == second.getRank()) {
			return "raise";
		} else if (intFirst - intSecond < 2 || intSecond - intFirst < 2
				&& first.getSuit() == second.getSuit()) {
			return "call";
		} else if (intFirst > 10 && intSecond > 10 && prevAction == "call") {
			return "raise";
		} else if (intFirst > 10 && intSecond > 10 && prevAction == "raise") {
			return "call";
		} else {
			return "fold";
		}
	}

	public int getRankInt(Rank rank) {
		int rankInt = 0;
		try {
			rankInt = Integer.parseInt(rank.rank());
		} catch (NumberFormatException e) {
			if (rank == Rank.TEN) {
				rankInt = 10;
			} else if (rank == Rank.JACK) {
				rankInt = 11;
			} else if (rank == Rank.QUEEN) {
				rankInt = 12;
			} else if (rank == Rank.KING) {
				rankInt = 13;
			} else if (rank == Rank.ACE) {
				rankInt = 14;
			}

		}
		return rankInt;
	}

	public Player compareAllHands(List<Player> players) {
		if (players.size() == 1) {
			return players.get(0);
		} else {
			Player first = players.get(0);
			Player second = players.get(1);
			String winner = compareHands(first, second);
			if (winner == "SPLIT") {
				// TODO a more elegant solution which works
				players.remove(second);
				players.remove(first);
			} else if (Integer.parseInt(winner) == second.getSeatIndex()) {
				players.remove(first);
			} else {
				players.remove(second);
			}
			return compareAllHands(players);
		}
	}
}
